#ifdef WIN32
#include <windows.h>
#include <io.h>
#pragma warning(disable:4996) /* _CRT_SECURE_NO_WARNINGS */
#else
#include <unistd.h>
#include <sys/syscall.h>
#endif /* WIN32 */
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>

#include "litelog.h"

/* YYYY-MM-dd HH-mm-ss, include the terminating null */
#define FORMATTED_DATETIME_LENGTH       20

int loglevel = DEBUG_LOG_LEVEL_WARN;                        /* default log level */
int enable_stdout = 1;                                      /* enable stdout by default */
int enable_stderr = 1;                                      /* enable stderr by default */
char __dbglog_time_format[] = "%Y-%m-%d %H:%M:%S";          /* Global time format string */

void STDERR(const char *errmsg)
{
	if (enable_stderr)
		perror(errmsg);
}

void STDOUT(const char *msg)
{
	if (enable_stdout)
		printf("%s", msg);
}


int dbglog(const char* message, int messagelevel, int fd, const char* source_file_name, int source_line_num)
{
	time_t systime;
	struct tm *curlocaltime;
	char curtime[FORMATTED_DATETIME_LENGTH];
	char* loglevel_title;
	char buf[MAX_LOG_MESSAGE_LENGTH + 1];
	int nResult = 0;

	/* We only write log when the message level exceed defined log level */
	if (messagelevel >= loglevel)
	{
		/* Get current time */
		if (time(&systime) != -1)
		{
			if ((curlocaltime = localtime(&systime)) != 0)
			{
				strftime(curtime, FORMATTED_DATETIME_LENGTH, __dbglog_time_format, curlocaltime);
				curtime[FORMATTED_DATETIME_LENGTH - 1] = 0;
			} /* if ((curlocaltime = localtime(&systime)) != 0) */
			else
			{
				curtime[0] = 0;
			} /* if ((curlocaltime = localtime(&systime)) != 0) */
		} /* if (time(&systime) != -1) */
		else
		{
			curtime[0] = 0;
		} /* else for  if (time(&systime) != -1) */

		/* Log level */
		switch(messagelevel)
		{
		case DEBUG_LOG_LEVEL_INFO:
			loglevel_title = DEBUG_LOG_LEVEL_INFO_TITLE;
			break;
		case DEBUG_LOG_LEVEL_WARN:
			loglevel_title = DEBUG_LOG_LEVEL_WARN_TITLE;
			break;
		case DEBUG_LOG_LEVEL_ERRO:
			loglevel_title = DEBUG_LOG_LEVEL_ERRO_TITLE;
			break;
		default:
			loglevel_title = DEBUG_LOG_LEVEL_INFO_TITLE;
			break;
		}

		/* Format the log message */
#ifdef WIN32
		if (source_file_name != 0)
		{
			_snprintf(buf, MAX_LOG_MESSAGE_LENGTH, "%s [%d:%d]: <%s> %s(%s|%d)\n", curtime, GetCurrentProcessId(), GetCurrentThreadId(), loglevel_title, message, source_file_name, source_line_num);
		}
		else
		{
			_snprintf(buf, MAX_LOG_MESSAGE_LENGTH, "%s [%d:%d]: <%s> %s(%s|%d)\n", curtime, GetCurrentProcessId(), GetCurrentThreadId(), loglevel_title, message);
		}
#else
		if (source_file_name != 0)
		{
			snprintf(buf, MAX_LOG_MESSAGE_LENGTH, "%s [%d:%d]: <%s> %s(%s|%d)\n", curtime, getpid(), (int)syscall(SYS_gettid), loglevel_title, message, source_file_name, source_line_num);
		}
		else
		{
			snprintf(buf, MAX_LOG_MESSAGE_LENGTH, "%s [%d:%d]: <%s> %s\n", curtime, getpid(), (int)syscall(SYS_gettid), loglevel_title, message);
		}
#endif
		buf[MAX_LOG_MESSAGE_LENGTH] = 0;

		if (fd > 0)
		{
			if ((nResult = _write(fd, buf, strlen(buf))) == -1)
			{
				switch (errno)
				{
				case EBADF:
					STDERR("Bad file descriptor!");
					break;
				 case ENOSPC:
					STDERR("No space left on device!");
					break;
				 case EINVAL:
					STDERR("Invalid parameter: buffer was NULL!");
					break;
				 default:
					/* An unrelated error occured */
					STDERR("Unexpected error when write to log file!");
					break;
				}
			}
		} /* if (fd > 0) */
		else
		{
			STDOUT(buf);
		} /* else for if (fd > 0) */
	} /* if (messagelevel >= loglevel) */

	return nResult;
}

int dbglogex(const char* message, int messagelevel, int fd, const char* source_file_name, int source_line_num, ...)
{
	va_list _va_list;
	char buf[MAX_LOG_MESSAGE_LENGTH + 1];

	memset(buf, 0, MAX_LOG_MESSAGE_LENGTH + 1);

	va_start(_va_list, source_line_num);                    /* Initial parameter list */
    _vsnprintf(buf, MAX_LOG_MESSAGE_LENGTH, message, _va_list);                       /* Pass the parameter list to function */
    va_end(_va_list);                                       /* End use parameter list */

    return dbglog(buf, messagelevel, fd, source_file_name, source_line_num);
}